package MapaStuff;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Random;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import Excepciones.FueraDeLimites;
import Ubicacion.Punto;

public class Mapa extends Observable{

	private final static int ALTO=20;
	private final static int ANCHO=20;
	private static Map<Punto, Hectarea> hectareas;
	static private Mapa unMapa= new Mapa();

	static public Mapa darMapa(){
		return unMapa;
	}
	
	private Mapa(){
		
		this.hectareas=new HashMap <Punto, Hectarea>();
		for (int i=1; i<=ANCHO;i++){
			for (int j=1; j<=ALTO; j++){
				this.hectareas.put(new Punto(i,j), new Hectarea (new Punto(i,j),new SuperficiePlana()));
				setChanged();
		        this.notifyObservers();
			}}
		for (int i=1; i<= 25;i++){
			hectareas.replace(new Punto(i,10), new Hectarea(new Punto(i,10), new SuperficieAgua()));
			setChanged();
	        this.notifyObservers();
		}

	}
	
	public void reparar(){
		for(int i=1; i<ALTO; i++){
			for(int j=1; j<ANCHO; j++){
				Hectarea hectarea = hectareas.get(new Punto(i,j));
				hectarea.sanar();
			}
		}
	}
	
	private void limites(Punto punto)throws FueraDeLimites{
		if(hectareas.containsKey(punto)){
			return;
		}
		throw new FueraDeLimites();
	}
	
	public void cargarHectarea(Hectarea hectarea)throws FueraDeLimites{
		
		Punto punto=hectarea.punto();
		limites(punto);
		this.hectareas.replace(punto, hectarea);
		setChanged();
        this.notifyObservers();
		
	}
	
	 public Hectarea darHectarea(Punto punto)throws FueraDeLimites{
		 Hectarea hect =  hectareas.get(punto);
		 if (hect == null) {
			 throw new FueraDeLimites();
		 }
		 return hect;
	}
	
	public ArrayList <Hectarea> hectareas() throws FueraDeLimites{
		ArrayList<Hectarea> listaDeHectareas = new ArrayList <Hectarea>();
		for (int i=1;i<ANCHO;i++){
			for (int j=1;j<ALTO;j++){
				listaDeHectareas.add(this.darHectarea(new Punto(i, j)));
			}
		}
		return listaDeHectareas;
	}

	public Hectarea hectareaLimite() throws FueraDeLimites{
		Random generador = new Random();
		Hectarea hectareaLimite = null;
		int i = generador.nextInt(3);
		switch (i) {
		case 0: hectareaLimite = this.hectareaEnElNorte(); break;
		case 1: hectareaLimite = this.hectareaEnElSur(); break;
		case 2: hectareaLimite = this.hectareaEnElEste(); break;
		case 3: hectareaLimite = this.hectareaEnElOeste(); break;
		}
		return hectareaLimite;		
	}
	
	
	private Hectarea hectareaEnElOeste() throws FueraDeLimites {
		Random generador = new Random ();
		int y = generador.nextInt(ALTO-1);
		return this.darHectarea(new Punto(1, y+1));
	}

	private Hectarea hectareaEnElEste() throws FueraDeLimites {
		Random generador = new Random ();
		int y = generador.nextInt(ALTO-1);
		return this.darHectarea(new Punto(ancho(), y+1));
	}

	private Hectarea hectareaEnElSur() throws FueraDeLimites{
		Random generador = new Random ();
		int x = generador.nextInt(ANCHO-1);
		return this.darHectarea(new Punto(x+1, alto()));
	}

	private Hectarea hectareaEnElNorte()throws FueraDeLimites {
		Random generador = new Random ();
		int x = generador.nextInt(ANCHO-1);
			return this.darHectarea(new Punto(x+1, 1));
	}

	public void actualizar() {		
	}
	

	public int ancho() {
		
		return ANCHO;
	}

	public int alto(){
		return ALTO;
	}

	public int getModeloDato(Punto posicion) {
		return hectareas.get(posicion).valorSuperficie();
	}

	public Element serializar(Document doc) {
		Element eleMapa=doc.createElement("Mapa");
		Element hectareas=doc.createElement("Hectareas");
		eleMapa.appendChild(hectareas);
		for(Hectarea hectarea: this.hectareas.values()){
			hectareas.appendChild(hectarea.serializar(doc));
		}
		return eleMapa;
	}

	public static Mapa hidratar(Node item) {
		unMapa.hectareas=new HashMap <Punto, Hectarea>();
		Element eleMapa=(Element)item;
		Element eleHec=(Element) eleMapa.getChildNodes().item(0);
		for(int i=0;i< eleHec.getChildNodes().getLength();i++){
			Hectarea hectarea=Hectarea.hidratar(eleHec.getChildNodes().item(i));
			unMapa.hectareas.put(hectarea.punto(),hectarea);
		}
		return unMapa;
	}

	public static Mapa nuevoMapa() {
		for (int i=1; i<=ANCHO;i++){
			for (int j=1; j<=ALTO; j++){
				hectareas.replace(new Punto(i,j), new Hectarea (new Punto(i,j),new SuperficiePlana()));
				
			}}
		for (int i=1; i<= 25;i++){
			hectareas.replace(new Punto(i,10), new Hectarea(new Punto(i,10), new SuperficieAgua()));
		} return darMapa();
	}

	
}
